home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / mus / misc / maplay1_2.lha / maplay / obuffer.cc < prev    next >
C/C++ Source or Header  |  1995-02-26  |  19KB  |  784 lines

  1. /*
  2.  *  @(#) obuffer.cc 1.17, last edit: 6/27/94 13:11:31
  3.  *  @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
  4.  *  @(#) Berlin University of Technology
  5.  *
  6.  *  Idea and first implementation for u-law output with fast downsampling by
  7.  *  Jim Boucher (jboucher@flash.bu.edu)
  8.  *
  9.  *  LinuxObuffer class written by
  10.  *  Louis P. Kruger (lpkruger@phoenix.princeton.edu)
  11.  *
  12.  *  IffObuffer class written by
  13.  *  Erik Johannessen (erik2@afrodite.kih.no)
  14.  *
  15.  *  This program is free software; you can redistribute it and/or modify
  16.  *  it under the terms of the GNU General Public License as published by
  17.  *  the Free Software Foundation; either version 2 of the License, or
  18.  *  (at your option) any later version.
  19.  *
  20.  *  This program is distributed in the hope that it will be useful,
  21.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  *  GNU General Public License for more details.
  24.  *
  25.  *  You should have received a copy of the GNU General Public License
  26.  *  along with this program; if not, write to the Free Software
  27.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  */
  29.  
  30. /*
  31.  *  Changes from version 1.1 to 1.2:
  32.  *    - new LinuxObuffer class, which works with 16 bit soundcards
  33.  *      like Gravis Ultrasound, SoundBlaster 16 or Pro Audio Spectrum 16,
  34.  *      if attached to /dev/dsp
  35.  *    - ShortObuffer renamed to FileObuffer
  36.  *    - If ULAW is defined:
  37.  *      - SparcObuffer feeds mono u-law output to an amd device (u-law format).
  38.  *        The required downsampling to 8 kHz in done in the synthesis filter.
  39.  *      - FileObuffer creates u-law output at 8 kHz instead of 16 bit PCM samples.
  40.  *    - O_NDELAY flag is cleared now after a successful open syscall
  41.  *      on /dev/audio (caused problems under Solaris)
  42.  *    - options -us, -uh and -ul should work now
  43.  *    - FileObuffer can handle incomplete write syscalls now
  44.  */
  45.  
  46. /*
  47.  *  19. Feb. 1995: IffObuffer class added by Erik Johannessen
  48.  *
  49. */
  50.  
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include <errno.h>
  55. #include <unistd.h>
  56. #include <fcntl.h>
  57. #include <sys/ioctl.h>
  58. #include <iostream.h>
  59. #include "obuffer.h"
  60. #include "header.h"
  61. #ifdef ULAW
  62. #include "ulaw.h"
  63. #endif
  64. #ifdef Iff
  65. typedef long LONG;
  66. typedef unsigned long ULONG;
  67. typedef unsigned short UWORD;
  68. typedef unsigned char UBYTE;
  69. /* ---------- Voice8Header ---------------------------------------------*/
  70. typedef LONG Fixed;    /* A fixed-point value, 16 bits to the left of
  71.              * the point and 16 to the right. A Fixed is a
  72.              * number of 2**16ths, i.e. 65536ths. */
  73. #define Unity 0x10000L    /* Unity = Fixed 1.0 = maximum volume */
  74.  
  75. /* sCompression: Choice of compression algorithm applied to the samples. */
  76. #define sCmpNone       0    /* not compressed */
  77. #define sCmpFibDelta   1    /* Fibonacci-delta encoding (Appendix C) */
  78.                 /* Could be more kinds in the future. */
  79. typedef struct {
  80.     ULONG oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  81.           repeatHiSamples,    /* # samples in the high octave repeat part */
  82.           samplesPerHiCycle;    /* # samples/cycle in high octave, else 0 */
  83.     UWORD samplesPerSec;    /* data sampling rate */
  84.     UBYTE ctOctave,        /* # of octaves of waveforms */
  85.           sCompression;        /* data compression technique used */
  86.     Fixed volume;        /* playback nominal volume from 0 to Unity
  87.                  * (full volume). Map this value into
  88.                  * the output hardware's dynamic range.
  89.                  */
  90.     } Voice8Header;
  91. #endif // Iff
  92.  
  93. #ifdef SunOS
  94. extern "C" int ioctl (int, int ...);        // Why...???
  95. #endif
  96.  
  97.  
  98. FileObuffer::FileObuffer (uint32 number_of_channels)
  99. {
  100. #ifdef DEBUG
  101.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  102.   {
  103.     cerr << "FileObuffer: number of channels has to be in [1, " <<  MAXCHANNELS << "] !\n";
  104.     exit (1);
  105.   }
  106. #endif
  107.  
  108. #ifdef ULAW
  109.   if (number_of_channels > 1)
  110.     cerr << "Are you sure you need stereo u-law output?\n";
  111. #endif
  112.   channels = number_of_channels;
  113.   for (int i = 0; i < number_of_channels; ++i)
  114.     bufferp[i] = buffer + i;
  115. }
  116.  
  117.  
  118. void FileObuffer::append (uint32 channel, int16 value)
  119. {
  120. #ifdef DEBUG
  121.   if (channel >= channels)
  122.   {
  123.     cerr << "illegal channelnumber in FileObuffer::append()!\n";
  124.     exit (1);
  125.   }
  126.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  127.   {
  128.     cerr << "FileObuffer: buffer overflow!\n";
  129.     exit (1);
  130.   }
  131. #endif
  132.  
  133. #ifdef ULAW
  134.   // convert 16-bit PCM sample to 8-bit ulaw:
  135.   *bufferp[channel] = linear2ulaw[value >> 3];
  136. #else
  137.   *bufferp[channel] = value;
  138. #endif
  139.   bufferp[channel] += channels;
  140. }
  141.  
  142.  
  143. void FileObuffer::write_buffer (int fd)
  144. {
  145.   int length = (int)((char *)bufferp[0] - (char *)buffer), writelength;
  146.  
  147.   if ((writelength = write (fd, (char *)buffer, length)) != length)
  148.   {
  149.     // buffer has not been written completely
  150.     if (writelength < 0)
  151.     {
  152.       perror ("write");
  153.       exit (1);
  154.     }
  155.     length -= writelength;
  156.     char *buffer_pos = (char *)buffer;
  157.     do
  158.     {
  159.       buffer_pos += writelength;
  160.       if ((writelength = write (fd, buffer_pos, length)) < 0)
  161.       {
  162.     perror ("write");
  163.     exit (1);
  164.       }
  165.     }
  166.     while (length -= writelength);
  167.   }
  168.  
  169.   for (int i = 0; i < channels; ++i)
  170.     bufferp[i] = buffer + i;
  171. }
  172.  
  173. #ifdef Iff
  174. // This Iff 8SVX code is just a quick hack.
  175. // Please note that the stereo output mode hasn't been testet much.
  176. // Erik Johannessen (erik2@afrodite.kih.no)
  177. IffObuffer::IffObuffer (uint32 number_of_channels, Header *header, char *filename)
  178. {
  179.   unsigned long dummy=0;
  180. Voice8Header vhdr;
  181.     char *fname;
  182.     long chan_type;
  183.     char tmpstr[32];
  184.  
  185.   channels = number_of_channels;
  186.   for (int i = 0; i < number_of_channels; ++i)
  187.     bufferp[i] = buffer + i*(OBUFFERSIZE>>1);
  188.  
  189.     if(channels==2){
  190.         chan_type=6L;
  191.         strcpy(fname2,"/tmp/maplay.");
  192.         sprintf(tmpstr,"%ld",getpid());
  193.         strcat(fname2,tmpstr);
  194.         fout2=fopen(fname2,"wb+");
  195.         if(fout2==NULL){
  196.             cerr << "Iff can't open output file for channel 1\n";    
  197.             exit(1);
  198.         }
  199.     }
  200.     else 
  201.         chan_type=2L;
  202.  
  203.     fname=(char *)malloc(strlen(filename)+6);
  204.     strcpy(fname,filename);
  205.     strcat(fname,".8svx");
  206.     fout=fopen(fname,"wb");
  207.     if(fout==NULL){
  208.         cerr << "Iff can't open output file for channel 0\n";
  209.         exit(1);
  210.     }
  211.     
  212.     free(fname);
  213.     fwrite("FORM",1,4,fout);
  214.     fwrite(&dummy,sizeof(dummy),1,fout);
  215.     fwrite("8SVX",1,4,fout);
  216.     fwrite("VHDR",1,4,fout);
  217.     dummy=sizeof(vhdr);
  218.     fwrite(&dummy,sizeof(dummy),1,fout);
  219.     vhdr.oneShotHiSamples=0;
  220.     vhdr.repeatHiSamples=0;
  221.     vhdr.samplesPerHiCycle=0;
  222.     vhdr.samplesPerSec=header->frequency();
  223.     vhdr.ctOctave=1;
  224.     vhdr.sCompression=sCmpNone;
  225.     vhdr.volume=Unity;
  226.     fwrite(&vhdr,sizeof(vhdr),1,fout);
  227.     dummy=sizeof(chan_type);
  228.     fwrite("CHAN",1,4,fout);
  229.     fwrite(&dummy,sizeof(dummy),1,fout);
  230.     fwrite(&chan_type,sizeof(chan_type),1,fout);
  231.     fwrite("BODY",1,4,fout);
  232.     dummy=0;
  233.     fwrite(&dummy,sizeof(dummy),1,fout);
  234.     totbytes=0;
  235. }
  236.  
  237. IffObuffer::~IffObuffer(void)
  238. {
  239.     unsigned long size;
  240.     char trbuf[2048];
  241.     long cnt;
  242.  
  243.     if(channels==2){    
  244.         fseek(fout2,0,SEEK_SET);
  245.         do{
  246.             cnt=fread(trbuf,1,2048,fout2);
  247.             fwrite(trbuf,1,cnt,fout);
  248.         }while(cnt==2048);
  249.         fclose(fout2);
  250.         remove(fname2);
  251.     }
  252.     size=totbytes+4+4+sizeof(Voice8Header)+12+4+4+4;
  253.     fseek(fout,4,SEEK_SET);
  254.     fwrite(&size,sizeof(size),1,fout);
  255.     fseek(fout,4+4+4+4+4+sizeof(Voice8Header)+12+4,SEEK_SET);
  256.     fwrite(&totbytes,sizeof(totbytes),1,fout);
  257.     fseek(fout,4+4+4+4+4,SEEK_SET);
  258.     fwrite(&totbytes,sizeof(totbytes),1,fout);
  259.     fclose(fout);
  260. }
  261.  
  262. void IffObuffer::append(uint32 channel,int16 value)
  263. {
  264. //    cerr << "channel " << channel << "\n";
  265.   *bufferp[channel] = value>>8;
  266.   bufferp[channel] ++;
  267. }
  268.  
  269. void IffObuffer::write_buffer(int)
  270. {
  271.     int length = (int)((char *)bufferp[0] - (char *)buffer);
  272.     fwrite((char *)buffer,length,1,fout);
  273.     if(channels==2){
  274.         fwrite((char *)buffer+(OBUFFERSIZE>>1),length,1,fout2);
  275.         length<<=1;
  276.     }
  277.     totbytes+=length;
  278.   for (int i = 0; i < channels; ++i)
  279.     bufferp[i] = buffer + i*(OBUFFERSIZE>>1);
  280. }
  281. #endif // Iff
  282.  
  283.  
  284. #ifdef Indigo
  285. IndigoObuffer::IndigoObuffer (uint32 number_of_channels, Header *header)
  286. {
  287. #ifdef DEBUG
  288.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  289.   {
  290.     cerr << "IndigoObuffer: number of channels has to be in [1, " <<  MAXCHANNELS << "] !\n";
  291.     exit (1);
  292.   }
  293. #endif
  294.   channels = number_of_channels;
  295.   for (int i = 0; i < number_of_channels; ++i)
  296.     bufferp[i] = buffer + i;
  297.  
  298.   // open an audio port and configure it:
  299.   ALconfig config;
  300.   if (!(config = ALnewconfig ()))
  301.   {
  302.     cerr << "ALnewconfig failed!\n";
  303.     exit (1);
  304.   }
  305.   ALsetwidth (config, AL_SAMPLE_16);
  306.   if (channels == 1)
  307.     ALsetchannels (config, AL_MONO);
  308.   else
  309.     ALsetchannels (config, AL_STEREO);
  310.   if (!(port = ALopenport ("MPEG audio player", "w", config)))
  311.   {
  312.     cerr << "can't allocate an audio port!\n";
  313.     exit (1);
  314.   }
  315.  
  316.   // set sample rate:
  317.   long pvbuffer[2] = { AL_OUTPUT_RATE, 0 };
  318.   pvbuffer[1] = header->frequency ();
  319.   ALsetparams (AL_DEFAULT_DEVICE, pvbuffer, 2);
  320.   ALfreeconfig (config);
  321. }
  322.  
  323.  
  324. IndigoObuffer::~IndigoObuffer (void)
  325. {
  326.   while (ALgetfilled (port) > 0)
  327.     sleep (1);
  328.   ALcloseport (port);
  329. }
  330.  
  331.  
  332. void IndigoObuffer::append (uint32 channel, int16 value)
  333. {
  334. #ifdef DEBUG
  335.   if (channel >= channels)
  336.   {
  337.     cerr << "illegal channelnumber in IndigoObuffer::append()!\n";
  338.     exit (1);
  339.   }
  340.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  341.   {
  342.     cerr << "IndigoObuffer: buffer overflow!\n";
  343.     exit (1);
  344.   }
  345. #endif
  346.   *bufferp[channel] = value;
  347.   bufferp[channel] += channels;
  348. }
  349.  
  350.  
  351. void IndigoObuffer::write_buffer (int)
  352. {
  353.   ALwritesamps (port, buffer, (long)(bufferp[0] - buffer));
  354.   for (int i = 0; i < channels; ++i)
  355.     bufferp[i] = buffer + i;
  356. }
  357. #endif // Indigo
  358.  
  359.  
  360. #ifdef SPARC
  361. int SparcObuffer::audio_fd = -1;
  362.  
  363. #ifdef ULAW
  364. SparcObuffer::SparcObuffer (Header *header, bool use_speaker, bool use_headphone, bool use_line_out)
  365. #else
  366. SparcObuffer::SparcObuffer (uint32 number_of_channels, Header *header,
  367.                 bool use_speaker, bool use_headphone, bool use_line_out)
  368. #endif
  369. {
  370. #ifndef ULAW
  371. #ifdef DEBUG
  372.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  373.   {
  374.     cerr << "SparcObuffer: 0 < number of channels < " << MAXCHANNELS << "!\n";
  375.     exit (1);
  376.   }
  377. #endif
  378. #endif    // !ULAW
  379.  
  380.   if (audio_fd < 0)
  381.   {
  382.     cerr << "Internal error: SparcObuffer::audio_fd has to be initialized\n"
  383.         "by SparcObuffer::class_suitable()!\n";
  384.     exit (1);
  385.   }
  386.  
  387.   audio_info info;
  388.   AUDIO_INITINFO (&info);
  389. #ifndef SunOS4_1_1
  390.   info.output_muted = False;
  391. #endif
  392.   info.play.port = 0;
  393.   if (use_speaker)
  394.     info.play.port |= AUDIO_SPEAKER;
  395.   if (use_headphone)
  396.     info.play.port |= AUDIO_HEADPHONE;
  397. #ifndef SunOS4_1_1
  398.   if (use_line_out)
  399.     info.play.port |= AUDIO_LINE_OUT;
  400. #endif
  401.  
  402. #ifdef ULAW
  403.   bufferp = buffer;
  404.  
  405.   // configure the amd device:
  406.   info.play.encoding = AUDIO_ENCODING_ULAW;
  407.   info.play.precision = 8;
  408.   info.play.channels = 1;
  409.   info.play.sample_rate = 8000;
  410. #else
  411.   channels = number_of_channels;
  412.   for (int i = 0; i < number_of_channels; ++i)
  413.     bufferp[i] = buffer + i;
  414.  
  415.   // configure the dbri device:
  416.   info.play.encoding = AUDIO_ENCODING_LINEAR;
  417.   info.play.precision = 16;
  418.   info.play.channels = channels;
  419.   info.play.sample_rate = header->frequency ();
  420. #endif    // !ULAW
  421.  
  422.   if (ioctl (audio_fd, AUDIO_SETINFO, &info))
  423.   {
  424.     perror ("configuration of /dev/audio failed");
  425.     exit (1);
  426.   }
  427. }
  428.  
  429.  
  430. SparcObuffer::~SparcObuffer (void)
  431. {
  432.   ioctl (audio_fd, AUDIO_DRAIN, NULL);
  433.   close (audio_fd);
  434. }
  435.  
  436.  
  437. void SparcObuffer::append (uint32 channel, int16 value)
  438. {
  439. #ifdef ULAW
  440. #ifdef DEBUG
  441.   if (bufferp - buffer >= OBUFFERSIZE >> 1)
  442.   {
  443.     cerr << "SparcObuffer: buffer overflow!\n";
  444.     exit (1);
  445.   }
  446. #endif
  447.  
  448.   // convert 16-bit PCM sample to 8-bit ulaw:
  449.   *bufferp++ = linear2ulaw[value >> 3];
  450. #else
  451. #ifdef DEBUG
  452.   if (channel >= channels)
  453.   {
  454.     cerr << "illegal channelnumber in SparcObuffer::append()!\n";
  455.     exit (1);
  456.   }
  457.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  458.   {
  459.     cerr << "SparcObuffer: buffer overflow!\n";
  460.     exit (1);
  461.   }
  462. #endif
  463.  
  464.   *bufferp[channel] = value;
  465.   bufferp[channel] += channels;
  466. #endif    // !ULAW
  467. }
  468.  
  469.  
  470. void SparcObuffer::write_buffer (int)
  471. {
  472. #ifdef ULAW
  473.   int length = (int)((char *)bufferp - (char *)buffer);
  474. #else
  475.   int length = (int)((char *)*bufferp - (char *)buffer);
  476. #endif
  477.   if (write (audio_fd, (char *)buffer, length) != length)
  478.   {
  479.     perror ("write to /dev/audio failed");
  480.     exit (1);
  481.   }
  482. #ifdef ULAW
  483.   bufferp = buffer;
  484. #else
  485.   for (int i = 0; i < channels; ++i)
  486.     bufferp[i] = buffer + i;
  487. #endif
  488. }
  489.  
  490.  
  491. int SparcObuffer::open_audio_device (void)
  492. {
  493.   int fd;
  494.  
  495.   if ((fd = open ("/dev/audio", O_WRONLY | O_NDELAY, 0)) < 0)
  496.     if (errno == EBUSY)
  497.     {
  498.       cerr << "Sorry, the audio device is busy!\n";
  499.       exit (1);
  500.     }
  501.     else
  502.     {
  503.       perror ("can't open /dev/audio for writing");
  504.       exit (1);
  505.     }
  506.  
  507.   // turn NDELAY mode off:
  508.   int flags;
  509.   if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
  510.   {
  511.     perror ("fcntl F_GETFL on /dev/audio failed");
  512.     exit (1);
  513.   }
  514.   flags &= ~O_NDELAY;
  515.   if (fcntl (fd, F_SETFL, flags) < 0)
  516.   {
  517.     perror ("fcntl F_SETFL on /dev/audio failed");
  518.     exit (1);
  519.   }
  520.   return fd;
  521. }
  522.  
  523.  
  524. #ifdef Solaris
  525. void SparcObuffer::get_device_type (int fd, audio_device *devtype)
  526. {
  527.   if (ioctl (fd, AUDIO_GETDEV, devtype))
  528.   {
  529.     perror ("ioctl AUDIO_GETDEV on /dev/audio");
  530.     exit (1);
  531.   }
  532. }
  533. #else
  534. int SparcObuffer::get_device_type (int fd)
  535. {
  536. #ifdef AUDIO_GETDEV
  537.   int devtype;
  538.   if (ioctl (fd, AUDIO_GETDEV, &devtype))
  539.   {
  540.     perror ("ioctl AUDIO_GETDEV on /dev/audio");
  541.     exit (1);
  542.   }
  543.   return devtype;
  544. #else
  545.   cerr << "SparcObuffer::get_device_type(): AUDIO_GETDEV ioctl not available!\n";
  546.   return -1;
  547. #endif
  548. }
  549. #endif    // !Solaris
  550.  
  551.  
  552. #ifdef ULAW
  553. bool SparcObuffer::class_suitable (uint32 number_of_channels, bool force_amd)
  554. #else
  555. bool SparcObuffer::class_suitable (void)
  556. #endif
  557. {
  558. #ifdef ULAW
  559.   if (number_of_channels > 1)
  560.   {
  561.     cerr << "Your audio hardware cannot handle more than one audio channel.\n"
  562.         "Please use the option -l or -r for stereo streams.\n";
  563.     return False;
  564.   }
  565. #endif
  566.  
  567.   // check for the dbri audio device:
  568.   audio_fd = open_audio_device ();
  569.  
  570. #ifdef ULAW
  571.   if (force_amd)
  572.     return True;
  573. #endif
  574.  
  575. #ifdef Solaris
  576.   audio_device devtype;
  577.   get_device_type (audio_fd, &devtype);
  578. # ifdef ULAW
  579.     if (!strcmp (devtype.name, "SUNW,am79c30"))
  580.       return True;
  581.     else if (!strcmp (devtype.name, "SUNW,dbri"))
  582.     {
  583.       cerr << "Your machine can produce CD-quality audio output,\n"
  584.           "but this binary was compiled for 8 kHz u-law ouput. (telephone quality)\n"
  585.           "Please recompile it without the ULAW define in COMPILERFLAGS.\n"
  586.           "(or use the -amd option to use this binary with low-quality output)\n";
  587.       close (audio_fd);
  588.       return False;
  589.     }
  590. # else
  591.     if (!strcmp (devtype.name, "SUNW,dbri"))
  592.       return True;
  593.     else if (!strcmp (devtype.name, "SUNW,am79c30"))
  594.     {
  595.       cerr << "Your machine can produce 8 kHz u-law audio output only,\n"
  596.           "but this binary was compiled for CD-quality output.\n"
  597.           "Please recompile it with ULAW defined in COMPILERFLAGS\n"
  598.           "or use it in stdout mode as an decoder only.\n";
  599.       close (audio_fd);
  600.       return False;
  601.     }
  602. # endif
  603. #else
  604.   // !Solaris
  605. # ifdef SunOS4_1_1
  606.     // no AUDIO_GETDEV under SunOS 4.1.1, so we have to assume that there is
  607.     // an amd device attached to /dev/audio
  608. #   ifdef ULAW
  609.       return True;
  610. #   else
  611.       cerr << "Your machine can produce 8 kHz u-law audio output only,\n"
  612.           "but this binary was compiled for CD-quality output.\n"
  613.           "Please recompile it with ULAW defined in COMPILERFLAGS\n"
  614.           "or use it in stdout mode as an decoder only.\n";
  615.       close (audio_fd);
  616.       return False;
  617. #   endif    // !ULAW
  618. # else
  619.     // SunOS 4.1.3
  620.     int device_type = get_device_type (audio_fd);
  621. #   ifdef ULAW
  622.       if (device_type == AUDIO_DEV_AMD)
  623.     return True;
  624.       else if (device_type == AUDIO_DEV_SPEAKERBOX)
  625.       {
  626.     cerr << "Your machine can produce CD-quality audio output,\n"
  627.         "but this binary was compiled for 8 kHz u-law ouput. (telephone quality)\n"
  628.         "Please recompile it without the ULAW define in COMPILERFLAGS.\n"
  629.         "(or use the -amd option to use this binary with low-quality output)\n";
  630.     close (audio_fd);
  631.     return False;
  632.       }
  633. #   else
  634.       if (device_type == AUDIO_DEV_SPEAKERBOX)
  635.     return True;
  636.       else if (device_type == AUDIO_DEV_AMD)
  637.       {
  638.     cerr << "Your machine can produce 8 kHz u-law audio output only,\n"
  639.         "but this binary was compiled for CD-quality output.\n"
  640.         "Please recompile it with ULAW defined in COMPILERFLAGS\n"
  641.         "or use it in stdout mode as an decoder only.\n";
  642.     close (audio_fd);
  643.     return False;
  644.       }
  645. #   endif    // !ULAW
  646. # endif    // !SunOS4_1_1
  647. #endif    // !Solaris
  648.  
  649. #ifndef SunOS4_1_1
  650.   close (audio_fd);
  651.   cerr << "Sorry, I don't recognize your audio device.\n"
  652. # ifdef ULAW
  653.       "Please try the -amd option or use the stdout mode.\n";
  654. # else
  655.       "Please use the stdout mode.\n";
  656. # endif
  657.   return False;
  658. #endif
  659. }
  660.  
  661. #endif    // SPARC
  662.  
  663.  
  664. #ifdef LINUX
  665. int LinuxObuffer::audio_fd = -1;
  666.  
  667. int LinuxObuffer::open_audio_device (void)
  668. {
  669.   int fd;
  670.  
  671.   if ((fd = open ("/dev/dsp", O_WRONLY | O_NDELAY, 0)) < 0)
  672.     if (errno == EBUSY)
  673.     {
  674.       cerr << "Sorry, the audio device is busy!\n";
  675.       exit (1);
  676.     }
  677.     else
  678.     {
  679.       perror ("can't open /dev/dsp for writing");
  680.       exit (1);
  681.     }
  682.  
  683.   // turn NDELAY mode off:
  684.   int flags;
  685.   if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
  686.   {
  687.     perror ("fcntl F_GETFL on /dev/audio failed");
  688.     exit (1);
  689.   }
  690.   flags &= ~O_NDELAY;
  691.   if (fcntl (fd, F_SETFL, flags) < 0)
  692.   {
  693.     perror ("fcntl F_SETFL on /dev/audio failed");
  694.     exit (1);
  695.   }
  696.   return fd;
  697. }
  698.  
  699.  
  700. LinuxObuffer::LinuxObuffer (uint32 number_of_channels, Header *header)
  701. {
  702. #ifdef DEBUG
  703.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  704.   {
  705.     cerr << "LinuxObuffer: 0 < number of channels < " << MAXCHANNELS << "!\n";
  706.     exit (1);
  707.   }
  708. #endif
  709.   channels = number_of_channels;
  710.   for (int i = 0; i < number_of_channels; ++i)
  711.     bufferp[i] = buffer + i;
  712.  
  713.   if (audio_fd < 0)
  714.   {
  715.     cerr << "Internal error, LinuxObuffer::audio_fd has to be initialized\n"
  716.         "by LinuxObuffer::class_suitable()!\n";
  717.     exit (1);
  718.   }
  719.  
  720.   // configure the device:
  721.   int play_precision = 16;
  722.   int play_stereo = channels-1;
  723.   int play_sample_rate = header->frequency ();
  724.  
  725.   if(
  726.       ioctl(audio_fd, SNDCTL_DSP_SAMPLESIZE, &play_precision) == -1 ||
  727.       ioctl(audio_fd, SNDCTL_DSP_STEREO, &play_stereo) == -1 ||
  728.       ioctl(audio_fd, SNDCTL_DSP_SPEED, &play_sample_rate) == -1
  729.     )
  730.   {
  731.     perror ("configuration of /dev/dsp failed");
  732.     exit (1);
  733.   }
  734. }
  735.  
  736.  
  737. LinuxObuffer::~LinuxObuffer (void)
  738. {
  739.   sleep (1);
  740.   close (audio_fd);
  741. }
  742.  
  743.  
  744. void LinuxObuffer::append (uint32 channel, int16 value)
  745. {
  746. #ifdef DEBUG
  747.   if (channel >= channels)
  748.   {
  749.     cerr << "illegal channelnumber in LinuxObuffer::append()!\n";
  750.     exit (1);
  751.   }
  752.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  753.   {
  754.     cerr << "buffer overflow!\n";
  755.     exit (1);
  756.   }
  757. #endif
  758.   *bufferp[channel] = value;
  759.   bufferp[channel] += channels;
  760. }
  761.  
  762.  
  763. void LinuxObuffer::write_buffer (int)
  764. {
  765.   int length = (int)((char *)bufferp[0] - (char *)buffer);
  766.   if (write (audio_fd, buffer, length) != length)
  767.   {
  768.     perror ("write to /dev/dsp failed");
  769.     exit (1);
  770.   }
  771.   for (int i = 0; i < channels; ++i)
  772.     bufferp[i] = buffer + i;
  773. }
  774.  
  775.  
  776. bool LinuxObuffer::class_suitable (uint32 number_of_channels)
  777. {
  778.   // open the dsp audio device:
  779.   audio_fd = open_audio_device ();
  780.   return True;
  781. }
  782.  
  783. #endif    /* LINUX */
  784.